/*
 * @Author: DaHuaZhuXi
 * @Date: 2020-11-26 09:23:29
 * @LastEditTime: 2021-01-14 21:25:48
 * @LastEditors: DaHuaZhuXi
 * @Description: 相关功能函数
 */
//创建rows*cols的地图二维数组
export function createMapDatas(op) {
  let ary = [];
  let center = [parseInt(op.rows / 2 - 1), parseInt(op.cols / 2 - 1)];

  //创建点数据
  let createPointObj = function (p) {
    return {
      x: p[0],
      y: p[1],
      type: 0, //0:点，1：线
      class: 0, //点的类别（战斗、事件等）
      isCurrent: false, //是否当前位置
      visit: false, // 已探索
      canVisit: false, //能否探索，
      isTarget: false, //是否探索目标点（用户点击的点）
      line: {}
    }
  }

  //创建线数据
  let createLineObj = function (p1, p2) {
    let _x = (p1[0] + p2[0]) / 2;
    let _y = (p1[1] + p2[1]) / 2;
    if (!getLineObjByPoint(_x, _y, ary)) {
      let point = createPointObj([_x, _y]);
      point.type = 1;
      point.line = {
        dir: p1[1] == p2[1] ? 0 : 1, //线方向 0：横，1：竖
      }
      return point
    }
  }


  //获取过滤后的当前坐标的四周坐标（隔开一个点）
  let getFilterRound2Points = function (point) {
    let x = point[0];
    let y = point[1];
    let round2Points = [[x - 2, y], [x, y - 2], [x + 2, y], [x, y + 2]];
    let round2Points_ = round2Points.filter(p => {
      if (p[0] < 0 || p[1] < 0 || p[0] > op.cols - 1 || p[1] > op.rows - 1) return false;
      return true;
    });
    return round2Points_
  }


  //创建点循环
  let createPointLoop = function (point) {
    let filterPoints = getFilterRound2Points(point);
    if (filterPoints.length == 0) return;

    //随机选择1-x个点
    let removeCount = filterPoints.length - 1; //单点模式
    for (let i = 0; i < removeCount; i++) {
      filterPoints.splice(common.random(0, filterPoints.length - 1), 1);
    }

    for (let i = 0; i < filterPoints.length; i++) {
      if (ary.filter(item => item.type == 0).length >= op.maxPoints) return;
      const p = filterPoints[i];

      //存储线数据
      let lineObj = createLineObj(point, p);
      if (lineObj) {
        ary.push(lineObj);
      }

      //如果该点不存在点数据则存储
      if (!getLineObjByPoint(p[0], p[1], ary)) {
        //存储点数据
        let pointObj = createPointObj(p);
        ary.push(pointObj);
      }
    }

    //单点模式
    createPointLoop(filterPoints[0])
  }

  let centerPointObj = createPointObj(center);
  centerPointObj.visit = true;
  centerPointObj.isCurrent = true;
  ary.push(centerPointObj);
  createPointLoop(center);

  //坐标偏移（使地图居中）
  let max = op.cols; //x,y最大值
  let offect = { offectX: 0, offectY: 0, centerX: 0, centerY: 0 }; //偏移坐标，和偏移的中心点
  let limit = { minX: max, maxX: 0, minY: max, maxY: 0 }; //x,y的界限
  ary.forEach(c => {
    limit.minX = c.x < limit.minX ? c.x : limit.minX;
    limit.maxX = c.x > limit.maxX ? c.x : limit.maxX;
    limit.minY = c.y < limit.minY ? c.y : limit.minY;
    limit.maxY = c.y > limit.maxY ? c.y : limit.maxY;
  });
  offect.centerX = (limit.maxX - limit.minX) / 2 + limit.minX;
  offect.centerY = (limit.maxY - limit.minY) / 2 + limit.minY;

  offect.offectX = Math.round((center[0] + 1 - offect.centerX));
  offect.offectY = Math.round((center[1] + 1 - offect.centerY));

  ary.forEach(c => {
    c.x += offect.offectX;
    c.y += offect.offectY;
  })

  return ary;
}

//地图类
export function Map(option, datas) {
  this.colors = config.mazeMapPointColors;
  this.mapPointClass = config.mazeMapPointClass;
  this.$map = option.$map;
  this.datas = datas;
  //获取视窗最小值，用于设置canvas的宽高
  this.minSize = Math.min(document.body.clientWidth, document.body.clientHeight);

  this.cols = option.cols; //划分格数
  this.center = [parseInt(this.cols / 2), parseInt(this.cols / 2)];
  this.unitSize = parseInt(this.minSize / this.cols);
  this.width = this.unitSize * this.cols;
  this.height = this.unitSize * this.cols;
  this.$map.setAttribute("width", this.width)
  this.$map.setAttribute("height", this.height)
  this.ctx = this.$map.getContext("2d");

  //更新
  this.update = function () {
    this.clear();
    this.drawMap();
    this.drawMapDatas();
  }

  //清空画布
  this.clear = function () {
    this.ctx.clearRect(0, 0, this.width, this.height);
  }

  //画地图数据
  this.drawMapDatas = function () {
    this.datas.forEach(item => {
      if (item.type == 1) {
        this.drawLine(item)
      } else {
        if (item.class == 0) {
          this.drawStrokeRect(item);
        } else {
          this.drawIcon(item)
        }
      }
    });
  }
  //画棋盘底图
  this.drawMap = function () {
    let color = "";
    for (let i = 0; i < this.cols; i++) {
      for (let j = 0; j < this.cols; j++) {
        if (i % 2 == 0) {
          color = j % 2 == 0 ? "#000" : "#222";
        } else {
          color = j % 2 == 0 ? "#222" : "#000";
        }
        this.drawPoint([j, i], color);
      }
    }
  }
  //两点间连线
  this.drawLine = function (item) {
    let size = this.unitSize;
    this.ctx.strokeStyle = this.getColor(item);
    this.ctx.lineWidth = 1;
    this.ctx.beginPath();

    if (item.line.dir == 0) { // 横向
      this.ctx.moveTo(size * item.x, size * item.y + size / 2);
      this.ctx.lineTo(size * item.x + size, size * item.y + size / 2);
    } else { //竖向
      this.ctx.moveTo(size * item.x + size / 2, size * item.y);
      this.ctx.lineTo(size * item.x + size / 2, size * item.y + size);
    }

    this.ctx.stroke();
  }
  //画图标
  this.drawIcon = function (item) {
    let size = this.unitSize;
    let text = eval('("\\u' + this.mapPointClass[item.class].icon + '")')
    this.ctx.font = `${size}px iconfont`;
    // 设置水平对齐方式
    this.ctx.textAlign = "center";
    // 设置垂直对齐方式
    this.ctx.textBaseline = "middle";
    //this.ctx.globalCompositeOperation = "source-atop"
    this.ctx.fillStyle = this.getColor(item);
    this.ctx.fillText(text, size * item.x + size / 2, size * item.y + size / 2);
  }
  //画点
  this.drawPoint = function (p, color) {
    let size = this.unitSize;
    this.ctx.fillStyle = color || "#222";
    this.ctx.fillRect(size * p[0], size * p[1], size, size);
  }
  //画矩形框
  this.drawStrokeRect = function (item) {
    let lineWidth = 4;
    this.ctx.strokeStyle = this.getColor(item);
    this.ctx.lineWidth = lineWidth;
    let size = this.unitSize;
    this.ctx.strokeRect(size * item.x + lineWidth / 2, size * item.y + lineWidth / 2, size - lineWidth, size - lineWidth);
  }
  // 根据点状态获取颜色
  this.getColor = function (item) {
    let color = "#fff";
    if (item.type == 0) { //点
      color = item.isCurrent ? this.colors["当前"] : item.visit ? this.colors["已探索"] : item.canVisit ? this.colors["可探索"] : this.colors["未探索"]
    } else { //线
      let cur = this.datas.find(c => c.isCurrent == true);
      let p1 = null;
      let p2 = null;
      if (item.line.dir == 1) { //竖向链接
        p1 = this.datas.find(c => c.x == item.x && c.y == item.y - 1);
        p2 = this.datas.find(c => c.x == item.x && c.y == item.y + 1);
      } else { //横向链接
        p1 = this.datas.find(c => c.y == item.y && c.x == item.x - 1);
        p2 = this.datas.find(c => c.y == item.y && c.x == item.x + 1);
      }
      //如果p1或p2中一个为当前点：则为“可探索”颜色
      if ((cur.x == p1.x && cur.y == p1.y) || (cur.x == p2.x && cur.y == p2.y)) {
        color = this.colors["可探索"]
      } else if (p1.visit && p2.visit) { //如果p1和p2均已探索
        color = this.colors["已探索"]
      } else {
        color = this.colors["未探索"]
      }
    }
    return color;
  }
}

// 设置地图点数据类别
export function setMapPointClass(mapDatas) {
  let endPointIndex = getEndPointIndex(mapDatas);
  let cla = config.mazeMapPointClass;
  mapDatas.forEach((item, index) => {
    if (item.type == 1) return; //跳过线类型
    if (item.visit) {
      item.class = 1;
    } else if (index == endPointIndex) {
      item.class = 2;
    } else {
      item.class = common.getNumberInAppoint([[0, cla[0].prob], [3, cla[3].prob], [4, cla[4].prob], [5, cla[5].prob]]);
    }
  })
  return mapDatas;
}

// 对某点探索成功
export function visitMapPoint(item, mapDatas) {
  item = item == "起点" ? mapDatas.find(c => c.class == 1) : item;
  mapDatas.map(c => {
    c.isCurrent = false;
    c.isTarget = false
  } );
  item.isCurrent = true;
  item.visit = true;
  mapDatas.map(c => c.canVisit = false);
  mapDatas.forEach(c => {
    if (
      pointCanVist(c, item, [-2, 0], mapDatas) ||
      pointCanVist(c, item, [0, -2], mapDatas) ||
      pointCanVist(c, item, [2, 0], mapDatas) ||
      pointCanVist(c, item, [0, 2], mapDatas)
    ) {
      c.canVisit = true;
    }
  });
}

// 设置某点为目标点
export function setTargetPoint(pointObj, mapDatas) {
  mapDatas.map(c => {
    c.isTarget = false
  } );
  if(pointObj){ pointObj.isTarget = true; }
}

// 当前坐标周围指定偏移坐标能否探索
export function pointCanVist(curPoint, centerPoint, offect, mapDatas) {
  return (curPoint.x == (centerPoint.x + offect[0]) && curPoint.y == (centerPoint.y + offect[1])) && isLink(curPoint, centerPoint, mapDatas);
}

// 2点之间是否链接
export function isLink(p1, p2, mapDatas) {
  if ((Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y) != 2)) return false;
  let centerPoint = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 }; //中间点坐标
  let center = mapDatas.find(c => c.x == centerPoint.x && c.y == centerPoint.y);
  if (center == undefined) return false;
  return center.type == 1
}

// 获取终点
function getEndPointIndex(mapDatas) {
  let start = mapDatas.find(item => item.visit == true);
  let endIndex = 0;
  let dist = 0;
  //找出离start最远的点的索引
  mapDatas.forEach((item, index) => {
    if (item.type == 1) return;
    let dist_ = Math.abs(item.x - start.x) + Math.abs(item.y - start.y);
    if (dist_ > dist) {
      dist = dist_;
      endIndex = index;
    }
  })
  return endIndex;
}

//根据坐标获取该点的线对象
function getLineObjByPoint(x, y, ary) {
  let o = ary.find(item => item.x == x && item.y == y);
  if (o) return o.line;
}